/**************************************************************************** **
 * Copyright (C) 2001-2020 Inhand Networks, Inc.
 **************************************************************************** **/

/* ************************************************************************** **
 *     MODULE NAME            : system
 *     LANGUAGE               : C
 *     TARGET ENVIRONMENT     : Any
 *     FILE NAME              : except.h
 *     FIRST CREATION DATE    : 2022/05/09
 * --------------------------------------------------------------------------
 *     Version                : 1.0
 *     Author                 : EExuke
 *     Last Change            : 2022/05/09
 *     FILE DESCRIPTION       : API exported to external moduels
** ************************************************************************** */
#ifndef _EXCEPT_H_
#define _EXCEPT_H_

#include <setjmp.h>

#define T Except_T
/*------------------Macro Definition-------------------------*/
#define RAISE(e) \
	Except_raise(&(e), __FILE__, __LINE__)

#define RERAISE \
	Except_raise(Except_frame.exception, Except_frame.file, Except_frame.line)

#define RETURN switch (Except_stack = Except_stack->prev,0) default: return

#define TRY do { \
				volatile int Except_flag; \
				Except_Frame Except_frame; \
				Except_frame.prev = Except_stack; \
				Except_stack = &Except_frame;  \
				Except_flag = setjmp(Except_frame.env); \
				if (Except_flag == Except_entered) {

#define EXCEPT(e) \
				if (Except_flag == Except_entered) \
					Except_stack = Except_stack->prev; \
				} else if (Except_frame.exception == &(e)) { \
					Except_flag = Except_handled;

#define ELSE \
				if (Except_flag == Except_entered) \
					Except_stack = Except_stack->prev; \
				} else { \
					Except_flag = Except_handled;

#define FINALLY \
				if (Except_flag == Except_entered) \
					Except_stack = Except_stack->prev; \
				} { \
				if (Except_flag == Except_entered) \
					Except_flag = Except_finalized;

#define END_TRY \
				if (Except_flag == Except_entered) \
					Except_stack = Except_stack->prev; \
				} if (Except_flag == Except_raised) \
					RERAISE; \
			} while (0)
/*------------------End of Macro Definition------------------*/

typedef struct T {
	char *reason;
} T;

typedef struct Except_Frame Except_Frame;

struct Except_Frame {
	Except_Frame *prev;
	jmp_buf env;
	const char *file;
	int line;
	const T *exception;
};

enum {
	Except_entered=0,
	Except_raised,
	Except_handled,
	Except_finalized
};

#ifdef WIN32
__declspec(thread)
#endif

extern Except_Frame *Except_stack;
extern const Except_T Assert_Failed;

/*------------------API Definition---------------------------*/
void Except_raise(const T *e, const char *file,int line);
/*------------------End of API Definition--------------------*/

#undef T
#endif /* End of _EXCEPT_H_ */

